// This file was added for video encoding/decoding
#include "Movie.h"
#include <stdio.h>


Movie::Movie(): frames(0), framePosition(0), width(0), height(0)
{
}


Movie::~Movie()
{
}

void Movie::Clear()
{
	if (frames)
	{
		delete[] frames;
		frames = 0;
	}

	framePosition = 0;
	frameCount = 0;
}

void Movie::SetDimension(unsigned int newWidth, unsigned int newHeight)
{
	width = newWidth;
	height = newHeight;
}

void Movie::ReadRawFromFile(const char *filename)
{
	Clear();

	if (width == 0 || height == 0)
		throw "Movie: Invalid dimension";


	FILE *f = fopen(filename, "rb");

	if (!f)
		throw "Movie: Cannot open file for reading";

	fseek(f, 0, SEEK_END);
	unsigned int filesize = ftell(f);
	fseek(f, 0, SEEK_SET);

	// For simplification, all frames are read into memory at once, instead of streaming frame by frame


	unsigned int grayFrameSize = width * height;
	unsigned int yuvFrameSize = grayFrameSize + grayFrameSize/2;
	unsigned int tmpFrameCount = filesize / yuvFrameSize;

	if (tmpFrameCount*yuvFrameSize != filesize)
	{
		fclose(f);

		throw "Movie: Size mismatch";
	}

	SetFrameCount(tmpFrameCount);

	unsigned char *grayImageData = new unsigned char[grayFrameSize];

	for(unsigned int i=0; i<tmpFrameCount; i++)
	{
		fread(grayImageData, sizeof(unsigned char), grayFrameSize, f);
		fseek(f, yuvFrameSize - grayFrameSize, SEEK_CUR);

		frames[i].SetDimension(width, height);
		frames[i].ReadRawFromData(grayImageData, grayFrameSize);
	}
	
	delete[] grayImageData;

	fclose(f);
}


void Movie::WriteRawToFile(const char *filename)
{
	FILE *f = fopen(filename, "wb");

	if (!f)
		throw "Movie: Cannot open file for writing";

	unsigned int crcbSize = Width()*Height()/2;
	unsigned char *crcb = new unsigned char[crcbSize];

	for(unsigned int j=0; j<crcbSize; j++)
		crcb[j] = 128;

	for(unsigned int i=0; i<frameCount; i++)
	{
		const unsigned char *imagedata = frames[i].ConstData();
		unsigned int imagesize = frames[i].Size();

		fwrite(imagedata, sizeof(unsigned char), imagesize, f);
		fwrite(crcb, sizeof(unsigned char), crcbSize, f);
	}

	delete[] crcb;

	fclose(f);
}

bool Movie::EndOfMovie() const
{
	return framePosition >= frameCount;
}

void Movie::SeekNext()
{
	framePosition++;
	if (framePosition >= frameCount)
		framePosition = frameCount;
}

Image* Movie::CurrentFrame()
{
	unsigned int index = framePosition;

	if (!frames || index >= frameCount)
		throw "Movie: Invalid frame index";

	return &frames[framePosition];
}

Image* Movie::PreviousFrame()
{
	unsigned int index = 0;

	if (framePosition > 0)
		index = framePosition-1;

	if (!frames || index >= frameCount)
		throw "Movie: Invalid frame index";

	return &frames[index];
}

void Movie::SetFrameCount(unsigned int newFrameCount)
{
	Clear();

	frameCount = newFrameCount;

	frames = new Image[frameCount];
}